/*
Timer
计时器大杂烩模块,时-分-秒分别计时
*/


module Timer (
    input clk,
    input clk_1_posedge,
    input rst_n,
    input [3:0] button_long,
    input [3:0] button_posedge,
    output wire [23:0] time_Byte,
    output reg [3:0] LED_out,
    output reg [5:0] dp_out
);

    parameter MAX_TIME = 59;

    reg [7:0] register [7:0];//定义一个一维8个8位的寄存器，用以存放控制信号，时间信号等
    /*
    register[0] 存放控制信号等,[7:6]模式,调整模式 00，计时，01，校时
    register[1] [7:6]存放当前校时位，00时，01分，10秒
    register[2] 空置
    register[3] 空置
    register[4] 存放小时高位和低位
    register[5] 存放分钟高位和低位
    register[6] 存放秒高位和低位
    register[7] 空置
    */
    wire c_SM,c_MH;
    wire [7:0] Hour,Minute,Second;
    reg [7:0] Hour_display;

    parameter MAX_black_time = 1000*50*499;//黑屏计时
    reg [31:0] black_count;

    parameter MAX_quick_press = 1000*50*299;//长按快速触发计时
    reg [31:0] quick_press;

    parameter MAX_calibration = 2'b01;//最大校时位置

    // assign {dp[4],dp[2],dp[0]} = register[1][2:0];
    // assign {dp[5],dp[3],dp[1]} = 3'b000;
    // assign dp = 6'b101011;
    
    reg [7:0] count_time = 0;        //计数
    // reg [3:0] H_byte = 0,L_byte = 0;
    wire [3:0] HH_temp,HL_temp,MH_temp,ML_temp,SH_temp,SL_temp;

    // reg [1:0] mode;         //调整模式 00，计时，01，校时
    reg timer_enable_n = 0;
    reg timer_rst_n = 1;
    // wire c_enable = (register[0][7:6] == 2'b00)? 1:0;

    assign time_Byte = {register[4],register[5],register[6]};

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            LED_out <= 4'b0000;
        end
        else begin
            case (register[0][7:6])
                2'b01:LED_out[2:0] <= 3'b001;
                2'b10:LED_out[2:0] <= 3'b010;
                default:LED_out[2:0] <= 3'b000;
            endcase
            if (register[0][4] == 1'b1 & Hour >= 8'd13) begin
                LED_out[3] <= 1'b1;
            end
            else LED_out[3] <= 1'b0;
        end
    end

    always @(posedge clk) begin       //屏幕控制
        case (register[0][7:6])
            2'b00:begin
                register[4] <= {HH_temp,HL_temp};
                register[5] <= {MH_temp,ML_temp};
                register[6] <= {SH_temp,SL_temp};
                dp_out <= 6'b101011;
            end
            2'b01:begin
                register[4] <= register[2][2]? 8'b11111111 : {HH_temp,HL_temp};
                register[5] <= register[2][1]? 8'b11111111 : {MH_temp,ML_temp};
                register[6] <= register[2][0]? 8'b11111111 : {SH_temp,SL_temp};
                dp_out <= 6'b101011;
            end
            2'b10:begin
                register[4] <= 8'b1010_1010;
                register[5] <= 8'b1111_1111;
                register[6] <= register[0][4]? {4'd1,4'd2}:{4'd2,4'd4};
                dp_out <= 6'b111111;
            end
            default:begin
                register[4] <= {HH_temp,HL_temp};
                register[5] <= {MH_temp,ML_temp};
                register[6] <= {SH_temp,SL_temp};
                dp_out <= 6'b101011;
            end
        endcase
        
        
        
    end
    // assign time_Byte = {HH_temp,HL_temp,MH_temp,ML_temp,SH_temp,SL_temp};

    always @(posedge clk or negedge rst_n) begin    //切换12/24进制功能,定义为register[0][7:6]=2'10位
        if (rst_n == 1'b0) begin
            register[0][4] <= 1'b0;
            Hour_display <= 8'd0;
        end
        else begin              //register[0][4]=0，24进制
            if (register[0][7:6] == 2'b10 & button_posedge[0] == 1'b1) begin
                register[0][4] <= ~register[0][4];
            end
            else begin
                register[0][4] <= register[0][4];
            end

            if (register[0][4] == 1'b1)begin
                if (Hour == 8'b0000_0000) begin
                    Hour_display <= 8'd12;
                end
                else if (Hour <= 8'd12) begin
                    Hour_display <= Hour;
                end
                else begin
                    Hour_display <= Hour - 8'd12;
                end
            end
            else Hour_display <= Hour;
            

        end
    end


    always @(posedge clk or negedge rst_n) begin    //选中位黑屏功能
        if (rst_n == 1'b0) begin
            register[2] <= 8'd0;
            black_count <= 0;
        end
        else begin
            if (register[0][7:6] == 2'b01) begin
                if (black_count == MAX_black_time) begin
                    black_count <= 0;
                    case (register[1][7:6])
                        2'b00:register[2][2] <= ~register[2][2];
                        2'b01:register[2][1] <= ~register[2][1];
                        2'b10:register[2][0] <= ~register[2][0];
                        default: register[2][2:0] <= 3'b000;
                    endcase
                end
                else if ((button_posedge[1] & ~button_long[1]) | (button_posedge[0] & ~button_long[0]) | register[3][0]) begin
                    black_count <= 0;
                    register[2][2:0] <= 3'b000;
                end
                else black_count <= black_count + 1'b1;
            end
            else begin
                register[2][2:0] <= 3'b000;
                black_count <= 0;
            end

            // if (button_posedge[1] | button_posedge[0]) begin
            //     black_count <= 0;
            //     register[2][2:0] <= 3'b000;
            // end
            // else register[2][2:0] <= register[2][2:0];
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            quick_press <= 0;
        end
        else begin
            if(button_long != 4'b0000) begin
                if (quick_press == MAX_quick_press) begin
                    quick_press <= 0;
                    register[3][3] <= (button_long[3])? 1'b1:1'b0;
                    register[3][2] <= (button_long[2])? 1'b1:1'b0;
                    register[3][1] <= (button_long[1])? 1'b1:1'b0;
                    register[3][0] <= (button_long[0])? 1'b1:1'b0;
                end
                else begin
                    quick_press <= quick_press + 1;
                    register[3][3:0] <= 0;
                end
            end
            else begin
                // register[3][3:0] <= 4'b0000;
                // register[3][3] <= (button_long[3] == 1'b0)? 
                register[3][3:0] <= button_posedge;
            end
        end
    end

    always @(posedge clk or negedge rst_n) begin    //主(校时)功能
        if (rst_n == 1'b0) begin
            register[0][7:6] <= 0;
            register[0][5] <= 0;
            register[1] <= 0;
        end
        else begin
            if (button_posedge[2] == 1'b1) begin//切换模式
                register[0][7:6] <= (register[0][7:6] == 2'b10)? 2'b00:(register[0][7:6] + 1'b1);
                register[1][7:6] <= 2'b00;
            end
            else register[0][7:6] <= register[0][7:6];

            if (button_posedge[1] == 1'b1 & button_long[1] != 1'b1 & register[0][7:6] == 2'b01) begin//切换校时位置
                register[1][7:6] <= (register[1][7:6] == MAX_calibration)? 2'b00:(register[1][7:6] + 1'b1);
            end
            else register[1][7:6] <= register[1][7:6];

            case (register[0][7:6])//判断模式，加一操作
                2'b01:begin
                    // 暂停计时
                    register[0][5] <= 1'b0;
                    if (register[3][0] == 1'b1) begin
                        case (register[1][7:6])
                            2'b00:register[1][2] <= 1;
                            2'b01:register[1][1] <= 1;
                            2'b10:register[1][0] <= 1;
                            default: register[1][2:0] <= 3'b000;
                        endcase
                    end
                    else register[1][2:0] <= 3'b000;
                end

                default: begin
                    register[0][5] <= 1'b1;
                    register[1][7:6] <= 2'b00;
                    // c_enable <= 1;
                end
                
                
            endcase

            // case (register[1][7:6])
            //     2'b00:register[1][2] <= 1;
            //     2'b01:register[1][1] <= 1;
            //     2'b10:register[1][0] <= 1;
            //     default: register[1][2:0] <= 3'b000;
            // endcase
        end
    end

    // wire c_SLSH,c_SHML,c_MLMH,c_MHHL,c_HLHH;

    Timer_Twice 
    #(
        .MAX_NUM (8'd23 )
    )
    u_Timer_Twice_H(
    	.clk      (clk      ),
        .NUM_in   (8'd0   ),
        .enable_n (1'b0 ),
        .set      (1'b0      ),
        .rst_n    (rst_n    ),
        .c_in     (c_MH & register[0][5] | register[1][2]     ),
        .NUM_out  (Hour  ),
        .c_out    (    )
    );
    Timer_Twice 
    #(
        .MAX_NUM (8'd59 )
    )
    u_Timer_Twice_M(
    	.clk      (clk      ),
        .NUM_in   (8'd0   ),
        .enable_n (1'b0 ),
        .set      (1'b0      ),
        .rst_n    (rst_n    ),
        .c_in     (c_SM & register[0][5] | register[1][1]     ),
        .NUM_out  (Minute  ),
        .c_out    (c_MH    )
    );
    Timer_Twice 
    #(
        .MAX_NUM (8'd59 )
    )
    u_Timer_Twice_S(
    	.clk      (clk      ),
        .NUM_in   (8'd0   ),
        .enable_n (1'b0 ),
        .set      (1'b0      ),
        .rst_n    (rst_n & ~button_long[1]    ),
        .c_in     (clk_1_posedge | register[1][0]     ),
        .NUM_out  (Second  ),
        .c_out    (c_SM    )
    );
    bin_bcd u_bin_bcd_H(
    	.en   (1'b1   ),
        .clk  (clk  ),
        .rst_n(rst_n),
        // .bin  (Hour  ),
        .bin  (Hour_display  ),
        .hund ( ),
        .ten  (HH_temp  ),
        .bits (HL_temp )
    );
    bin_bcd u_bin_bcd_M(
    	.en   (1'b1   ),
        .clk  (clk  ),
        .rst_n(rst_n),
        .bin  (Minute  ),
        .hund ( ),
        .ten  (MH_temp  ),
        .bits (ML_temp )
    );
    bin_bcd u_bin_bcd_S(
    	.en   (1'b1   ),
        .clk  (clk  ),
        .rst_n(rst_n),
        .bin  (Second  ),
        .hund ( ),
        .ten  (SH_temp  ),
        .bits (SL_temp )
    );
    
    
    
    

    // Timer_Single //HH
    // #(
    //     .MAX_NUM (2 )
    // )
    // Timer_SingleHH( 
    // 	.clk           (clk               ),
    //     .NUM_in        (4'd0            ),
    //     .enable_n      (1'b0 | register[2][2]          ),
    //     .set           (1'b0               ),
    //     .rst_n         (rst_n             ),
    //     .c_in          (c_HLHH            ),
    //     .NUM_out       (HH_temp               ),
    //     .c_out         (             )
    // );
    // Timer_Single //!HL bughere
    // #(
    //     .MAX_NUM (3 )
    // )
    // Timer_SingleHL( 
    // 	.clk           (clk               ),
    //     .NUM_in        (4'd0            ),
    //     .enable_n      (1'b0 | register[2][2]          ),
    //     .set           (1'b0               ),
    //     .rst_n         (rst_n             ),
    //     .c_in          ((c_MHHL & register[0][5]) | register[1][2]               ),
    //     .NUM_out       (HL_temp               ),
    //     .c_out         (c_HLHH             )
    // );
    // Timer_Single //MH
    // #(
    //     .MAX_NUM (5 )
    // )
    // Timer_SingleMH( 
    // 	.clk           (clk               ),
    //     .NUM_in        (4'd0            ),
    //     .enable_n      (1'b0 | register[2][1]         ),
    //     .set           (1'b0               ),
    //     .rst_n         (rst_n             ),
    //     .c_in          (c_MLMH              ),
    //     .NUM_out       (MH_temp               ),
    //     .c_out         (c_MHHL             )
    // );
    // Timer_Single //ML
    // #(
    //     .MAX_NUM (9 )
    // )
    // Timer_SingleML( 
    // 	.clk           (clk               ),
    //     .NUM_in        (4'd0            ),
    //     .enable_n      (1'b0 | register[2][1]          ),
    //     .set           (1'b0               ),
    //     .rst_n         (rst_n             ),
    //     .c_in          ((c_SHML & register[0][5]) | register[1][1]               ),
    //     .NUM_out       (ML_temp               ),
    //     .c_out         (c_MLMH             )
    // );

    // Timer_Single //SH
    // #(
    //     .MAX_NUM (5 )
    // )
    // Timer_SingleSH(
    // 	.clk           (clk           ),
    //     .NUM_in        (4'd0        ),
    //     .enable_n      (1'b0 & register[2][0]       ),
    //     .set           (1'b0           ),
    //     .rst_n         (rst_n & ~button_long[1]       ),//长按重置
    //     .c_in          (c_SLSH          ),
    //     .NUM_out       (SH_temp           ),
    //     .c_out         (c_SHML         )
    // );
    // Timer_Single //SL
    // #(
    //     .MAX_NUM (9 )
    // )
    // Timer_SingleSL( 
    // 	.clk           (clk               ),
    //     .NUM_in        (4'd0            ),
    //     .enable_n      (1'b0 | register[2][0]          ),
    //     .set           (1'b0               ),
    //     .rst_n         (rst_n & ~button_long[1]              ),//长按重置
    //     .c_in          ((clk_1_posedge & register[0][5]) | register[1][0]               ),
    //     .NUM_out       (SL_temp               ),
    //     .c_out         (c_SLSH             )
    // );
    

    
endmodule

module Timer_Twice (
    input clk,
    input [7:0] NUM_in,
    input enable_n,
    input set,
    input rst_n,
    input c_in,
    output wire [7:0] NUM_out,
    output reg c_out
);
    parameter [8:0] MAX_NUM = 8'd59;

    reg [7:0] Counter = 0;

    assign NUM_out = enable_n? 8'b11111111:Counter;

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            Counter <= 8'd0;
        end
        else begin
            if (set == 1'b1) begin
                Counter <= NUM_in;
            end
            else begin
                if (enable_n == 1'b0) begin
                    if (c_in == 1'b1) begin
                        Counter <= (Counter == MAX_NUM)? 1'b0:(Counter + 1'b1);
                        c_out <= (Counter == MAX_NUM)? 1'b1:1'b0;
                    end
                    else begin
                        Counter <= Counter;
                        c_out <= 0;
                    end
                end
                else begin
                    Counter <= Counter;
                end
            end
            
        end
    end

    
endmodule

/*
module Timer_Single (
    input clk,
    input [3:0] NUM_in,
    input enable_n,
    input set,
    input rst_n,
    input c_in,
    output wire [3:0] NUM_out,
    output reg c_out
);
    parameter MAX_NUM = 4'd9;

    reg [3:0] Counter = 0;

    assign NUM_out = enable_n? 4'b1111:Counter;

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            Counter <= 4'd0;
        end
        else begin
            if (set == 1'b1) begin
                Counter <= NUM_in;
            end
            else begin
                if (enable_n == 1'b0) begin
                    if (c_in == 1'b1) begin
                        Counter <= (Counter == MAX_NUM)? 0:(Counter + 1);
                        c_out <= (Counter == MAX_NUM)? 1:0;
                    end
                    else begin
                        Counter <= Counter;
                        c_out <= 0;
                    end
                end
                else begin
                    Counter <= Counter;
                end
            end
            
        end
    end
    
endmodule*/